﻿#include "Parser.h"

#include <fstream>
#include <iostream>
#include <string>

Parser::Parser()
{
    m_net_options = std::make_shared<std::vector<std::shared_ptr<Options>>>();
    m_names       = std::make_shared<std::vector<std::string>>();
}

bool Parser::LoadJsonOptionsFromText(const std::string &json_text)
{
    nlohmann::json options = nlohmann::json::parse(json_text);
    return ParseJsonOptions(options);
}

bool Parser::LoadJsonOptionsFromFile(const std::string &filepath)
{
    std::ifstream ifs(filepath);
    if (!ifs.is_open()) return false;
    nlohmann::json options = nlohmann::json::parse(ifs);
    return ParseJsonOptions(options);
}

bool Parser::ParseJsonOptions(const nlohmann::json &options)
{
    if (!options.is_object()) return false;
    auto &json_net_options        = options["net"];
    auto &json_net_layers_options = json_net_options["layers"];
    if (json_net_options.is_object() && json_net_layers_options.is_array())
    {
        m_net_options->push_back(JsonToOptions(json_net_options));
        int size = json_net_layers_options.size();
        for (int i = 0; i < size; i++)
        {
            auto &json_layer_options = json_net_layers_options[i];
            if (json_layer_options.is_object())
            {
                m_net_options->push_back(JsonToOptions(json_layer_options));
            }
        }
    }

    return true;
}

std::shared_ptr<Options> Parser::JsonToOptions(const nlohmann::json &json_options)
{
    auto options = std::make_shared<Options>();
    auto name    = json_options["name"];
    if (name.is_string()) options->SetName(name.get<std::string>());

    for (auto it = json_options.begin(); it != json_options.end(); ++it)
    {
        auto &key   = it.key();
        auto &value = it.value();
        if (value.is_string())
        {
            options->SetOption(key, value.get<std::string>());
        }
        else if (value.is_number())
        {
            options->SetOption(key, std::to_string(value.get<double>()));
        }
        else if (value.is_boolean())
        {
            options->SetOption(key, value.get<bool>() ? "true" : "false");
        }
        else
        {
            // std::cerr << "unknown type: key = " << key << std::endl;
        }
    }

    return options;
}
